package com.rk.jarjuggler.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.rk.jarjuggler.model.DirNode;
import com.rk.jarjuggler.model.LibNode;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;

public class NodeLoader {
    private HttpClient httpClient;
    private BlockingQueue<WorkItem> workQueue = new PriorityBlockingQueue<WorkItem>(1000, new WorkItemComparator());

    private String dirRegex = "^<IMG SRC=\"/icons/folder.gif\" ALT=\"\\[DIR\\]\"> <A HREF=\"([\\d\\.\\w\\-]+)/\">.*$";
    private String jarRegex = "<A HREF=\"([\\w\\-.]+\\.jar)\">";

    private Pattern dirPattern;
    private Pattern jarPattern;

    public NodeLoader() {
        httpClient = new HttpClient();
//        httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
        initRegex();
    }

    public Queue<WorkItem> getWorkQueue() {
        return workQueue;
    }

    private void initRegex(){
        dirPattern = Pattern.compile(dirRegex, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
        jarPattern = Pattern.compile(jarRegex, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    }

    public DirNode loadTree(String url){
        WorkItem workItem = new WorkItem(new DirNode(), "Root", url);
        DirNode root = loadNode(workItem);

        while (!workQueue.isEmpty()) {
            loadNode(workQueue.poll());
        }

        return root;
    }

    public DirNode loadNode(WorkItem workItem) {
        try {
            String url = workItem.getUrl();
            String content = fetchPage(url);
            List<String> dirUrls = getDirUrls(content);
            if (dirUrls.isEmpty()) {
                return createLibNode(workItem, content, url);
            } else {
                return createDirNode(workItem, url, dirUrls);
            }
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            return null;
        }
    }

    private DirNode createDirNode(WorkItem workItem, String url, List<String> dirUrls) {
        DirNode newNode = new DirNode(workItem.getParent(), workItem.getName(), url);
        for (String subdir : dirUrls) {
            workQueue.add(new WorkItem(newNode, subdir, url + subdir + "/"));
        }
        return newNode;
    }

    private LibNode createLibNode(WorkItem workItem, String content, String url) {
        LibNode newNode = new LibNode(workItem.getParent(), workItem.getName());
        List<String> jarUrls = getJarUrls(content);
        if (!jarUrls.isEmpty()){
            for (String s : jarUrls) {
                System.out.println("s = " + s);
                if (s.endsWith("sources.jar")) {
                    newNode.setSrcUrl(url + s);
                } else if (s.endsWith("javadoc.jar")){
                    newNode.setJavadocUrl(url + s);
                } else {
                    newNode.setJarUrl(url + s);
                }
            }
        }
        return newNode;
    }

    public List<String> getDirUrls(String content){
        Matcher matcher = dirPattern.matcher(content);

        List<String> results = new ArrayList<String>();
        while (matcher.find()){
            results.add(matcher.group(1));
        }

        return results;
    }

    public List<String> getJarUrls(String content){
        Matcher matcher = jarPattern.matcher(content);

        List<String> results = new ArrayList<String>();
        while (matcher.find()){
            results.add(matcher.group(1));
        }

        return results;
    }


    public String fetchPage(String url) throws IOException {
        GetMethod get = new GetMethod(url);
        get.setFollowRedirects(false);
        int responseCode = httpClient.executeMethod(get);
        System.out.println("Response code was <" + responseCode + "> for URL: " + url);
        if (responseCode != HttpStatus.SC_OK){
            return "";
        } else  {
            return get.getResponseBodyAsString();
        }
    }

    public void displayWorkQueue(){
        for (WorkItem item : workQueue) {
            System.out.println("item.getUrl() = " + item.getUrl());
        }
    }

}
